//----BEGIN LICENSE----//
/*****************************************************************\
** prevalentLite - sqlite3 persistence object library 
**
** Copyright (C) 2008 Philip R. Schuchardt
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
**
*****************************************************************/
//----END LICENSE----//

/*!
  \class plData

  \brief Abstract Base class of all database aware datatypes

Classes that inhert plData, (plDouble, plInt, plPointer, etc...) know how to read and write out of a sqlite3 database.  For plData to understand where to read and write in the database, the object must set it up by calling Setup() .  If the object doesn't call Setup(), the database will through an error (Debug mode only) and data will not be saved or retrieved.  Once plData is set-up, the user should be able to use the data transparently.  See plObject for an example.

<b>Making your own database aware data:</b>

Sometimes it useful to create your own database aware data.  This is very easy to do, just inhert plData, reimplement plData::Bind() and plData::Column(), and overload plData::GetClassName().  The data must fit into one cell in the database.  See the sqlite3 documentation for details.  It's usually useful to overload several of the operators to add data transparenty to your custom class.  I recommend looking at plInt.cpp and plInt.h for a good example.

  */

//Our includes
#include "plData.h"
#include "plObject.h"
#include "plDatabase.h"

///////////////////////////////////// Static Data ////////////////////////////////////////////

std::map<std::string, plData::ReferanceData*> plData::Lookup;

/////////////////////////////////////// Public /////////////////////////////////////////////////////

//!Constructor
plData::plData() {
    Init();
     }

//!Destructor
plData::~plData() {
    //sqlite3_finalize(Statement);
}

//!Initializes the data
void plData::Init() {
    Owner = NULL;
    Referance = NULL;
    Cached = false;
    Disabled = false;
  }

//!Copy constructor
plData::plData(const plData& data) {
    //If data is setup correctly copy it.
    Init();

    //Only need to copy if it's disabled
    Disabled = data.Disabled;

}

/*!
\brief Gets the sqlite column name for this data

SYSTEM FUNCTION SHOULD NOT BE CALLED BY THE USER
*/
const std::string& plData::GetColumnName() const {
    return Referance->ColumnName;
}

/*!
\brief Gets the sqlite table name for this data

SYSTEM FUNCTION SHOULD NOT BE CALLED BY THE USER
*/
const std::string& plData::GetTableName() const {
    return Referance->TableName;
}

/*!
\brief Gets the owner object

SYSTEM FUNCTION SHOULD NOT BE CALLED BY THE USER

\return The object that owns this data
*/
plObject* plData::GetOwner() const {
    return Owner;
}


/*!
\brief Setups up the data

Should be called in the construct of an object

\param columnName - The name of the data
\param owner - The object that owns this data

*/
void plData::Setup(const std::string& columnName, plObject* owner) {

    std::string key;
    key.append(columnName);
    key.append(owner->_GetClassName());

    std::map<std::string, ReferanceData*>::iterator iter;

    //If key doesn't exist in the lookup
    if((iter = Lookup.find(key)) == Lookup.end()) {
        //We need to create the Referance
        Referance = new ReferanceData();
        Referance->ColumnName = columnName;
        Referance->TableName = owner->_GetClassName();
        Lookup[key] = Referance;
    } else {
        //We found the referance, use it
        Referance = (*iter).second;
    }

    Owner = owner;
}

/*!
\brief Gets the data from the database if needed

Should called by subclasses to get there data out of the database.

*/
void plData::GetData() const {
    if(!Cached && !Disabled) {
        plDatabase* database = GetDatabase();

        //We need to strip away the const so we can allow for Caching
        plData* tmp = const_cast<plData*>(this);
        tmp->Cached = database->GetData(tmp);
    }
}

/*!
\brief Sets the data in the database

Calles the database to update the table with new data
*/
void plData::SetData() {
    if(!Disabled) {
        plDatabase* database = GetDatabase();
        Cached = database->SetData(this);
    }
}

/*!
  \brief If the data is setup or not
  \return True if the user called Setup() and fail it they haven't
  */
bool plData::IsSetup() {
    return Referance != NULL;
}

/*!
 \brief Gets the current open database
 */
plDatabase* plData::GetDatabase()  {
    return plDatabase::GetDatabase();
}



